use std::{
    fs::{self, File},
    io::{BufReader, BufWriter},
    path::{Path, PathBuf},
    sync::Mutex,
};

use anyhow::{Context, Result};
use serde::Serialize;
use serde::de::DeserializeOwned;

use crate::domain::{Project, ProjectWeather};

#[allow(dead_code)]
pub struct JsonDataService {
    projects_path: PathBuf,
    project_weathers_path: PathBuf,
    lock: Mutex<()>,
}

#[allow(dead_code)]
impl JsonDataService {
    pub fn new(base_dir: impl AsRef<Path>) -> Result<Self> {
        let base_dir = base_dir.as_ref();
        if !base_dir.exists() {
            fs::create_dir_all(base_dir)
                .with_context(|| format!("创建配置目录失败: {}", base_dir.display()))?;
        }

        let projects_path = base_dir.join("projects.json");
        let project_weathers_path = base_dir.join("project-weathers.json");

        let service = Self {
            projects_path,
            project_weathers_path,
            lock: Mutex::new(()),
        };

        service.ensure_file_exists::<Project>(&service.projects_path)?;
        service.ensure_file_exists::<ProjectWeather>(&service.project_weathers_path)?;

        Ok(service)
    }

    pub fn get_all_projects(&self) -> Result<Vec<Project>> {
        let _guard = self.lock.lock().unwrap();
        self.read_json::<Project>(&self.projects_path)
    }

    pub fn get_project_by_id(&self, id: i32) -> Result<Option<Project>> {
        let projects = self.get_all_projects()?;
        Ok(projects.into_iter().find(|p| p.id == id))
    }

    pub fn get_project_by_name(&self, name: &str) -> Result<Option<Project>> {
        let projects = self.get_all_projects()?;
        Ok(projects.into_iter().find(|p| p.project_name == name))
    }

    pub fn add_project(&self, mut project: Project) -> Result<Project> {
        let _guard = self.lock.lock().unwrap();
        let mut projects = self.read_json::<Project>(&self.projects_path)?;

        let next_id = projects.iter().map(|p| p.id).max().unwrap_or(0) + 1;
        project.id = next_id;
        projects.push(project.clone());

        self.write_json(&self.projects_path, &projects)?;
        Ok(project)
    }

    pub fn update_project(&self, project: Project) -> Result<bool> {
        let _guard = self.lock.lock().unwrap();
        let mut projects = self.read_json::<Project>(&self.projects_path)?;

        if let Some(idx) = projects.iter().position(|p| p.id == project.id) {
            projects[idx] = project;
            self.write_json(&self.projects_path, &projects)?;
            Ok(true)
        } else {
            Ok(false)
        }
    }

    pub fn delete_project(&self, id: i32) -> Result<bool> {
        let _guard = self.lock.lock().unwrap();
        let mut projects = self.read_json::<Project>(&self.projects_path)?;
        let len_before = projects.len();
        projects.retain(|p| p.id != id);

        if projects.len() == len_before {
            return Ok(false);
        }

        self.write_json(&self.projects_path, &projects)?;

        // 删除关联气象记录
        let mut weathers = self.read_json::<ProjectWeather>(&self.project_weathers_path)?;
        weathers.retain(|w| w.project_id != id);
        self.write_json(&self.project_weathers_path, &weathers)?;

        Ok(true)
    }

    pub fn get_all_project_weathers(&self) -> Result<Vec<ProjectWeather>> {
        let _guard = self.lock.lock().unwrap();
        self.read_json::<ProjectWeather>(&self.project_weathers_path)
    }

    pub fn get_project_weathers_by_project_id(
        &self,
        project_id: i32,
    ) -> Result<Vec<ProjectWeather>> {
        let weathers = self.get_all_project_weathers()?;
        Ok(weathers
            .into_iter()
            .filter(|w| w.project_id == project_id)
            .collect())
    }

    pub fn get_project_weather_by_id(&self, id: i64) -> Result<Option<ProjectWeather>> {
        let weathers = self.get_all_project_weathers()?;
        Ok(weathers.into_iter().find(|w| w.id == id))
    }

    pub fn add_project_weather(&self, mut weather: ProjectWeather) -> Result<ProjectWeather> {
        let _guard = self.lock.lock().unwrap();
        let mut weathers = self.read_json::<ProjectWeather>(&self.project_weathers_path)?;

        let next_id = weathers.iter().map(|w| w.id).max().unwrap_or(0) + 1;
        weather.id = next_id;
        weathers.push(weather.clone());

        self.write_json(&self.project_weathers_path, &weathers)?;
        Ok(weather)
    }

    pub fn add_project_weather_range(&self, mut weather_list: Vec<ProjectWeather>) -> Result<()> {
        let _guard = self.lock.lock().unwrap();
        let mut weathers = self.read_json::<ProjectWeather>(&self.project_weathers_path)?;
        let mut next_id = weathers.iter().map(|w| w.id).max().unwrap_or(0);

        for weather in &mut weather_list {
            next_id += 1;
            weather.id = next_id;
            weathers.push(weather.clone());
        }

        self.write_json(&self.project_weathers_path, &weathers)?;
        Ok(())
    }

    pub fn update_project_weather(&self, weather: ProjectWeather) -> Result<bool> {
        let _guard = self.lock.lock().unwrap();
        let mut weathers = self.read_json::<ProjectWeather>(&self.project_weathers_path)?;

        if let Some(idx) = weathers.iter().position(|w| w.id == weather.id) {
            weathers[idx] = weather;
            self.write_json(&self.project_weathers_path, &weathers)?;
            Ok(true)
        } else {
            Ok(false)
        }
    }

    pub fn delete_project_weather(&self, id: i64) -> Result<bool> {
        let _guard = self.lock.lock().unwrap();
        let mut weathers = self.read_json::<ProjectWeather>(&self.project_weathers_path)?;
        let len_before = weathers.len();
        weathers.retain(|w| w.id != id);

        if weathers.len() == len_before {
            return Ok(false);
        }

        self.write_json(&self.project_weathers_path, &weathers)?;
        Ok(true)
    }

    pub fn delete_project_weathers_by_project_id(&self, project_id: i32) -> Result<()> {
        let _guard = self.lock.lock().unwrap();
        let mut weathers = self.read_json::<ProjectWeather>(&self.project_weathers_path)?;
        weathers.retain(|w| w.project_id != project_id);
        self.write_json(&self.project_weathers_path, &weathers)?;
        Ok(())
    }

    fn ensure_file_exists<T>(&self, path: &Path) -> Result<()>
    where
        T: Serialize,
    {
        if !path.exists() {
            let writer = BufWriter::new(File::create(path)?);
            serde_json::to_writer_pretty(writer, &Vec::<T>::new())
                .with_context(|| format!("初始化 JSON 文件失败: {}", path.display()))?;
        }
        Ok(())
    }

    fn read_json<T>(&self, path: &Path) -> Result<Vec<T>>
    where
        T: DeserializeOwned,
    {
        if !path.exists() {
            return Ok(Vec::new());
        }

        let file = File::open(path)?;
        if file.metadata()?.len() == 0 {
            return Ok(Vec::new());
        }

        let reader = BufReader::new(file);
        let items = serde_json::from_reader(reader)
            .with_context(|| format!("读取 JSON 文件失败: {}", path.display()))?;
        Ok(items)
    }

    fn write_json<T>(&self, path: &Path, data: &[T]) -> Result<()>
    where
        T: Serialize,
    {
        let file = File::create(path)?;
        let writer = BufWriter::new(file);
        serde_json::to_writer_pretty(writer, data)
            .with_context(|| format!("写入 JSON 文件失败: {}", path.display()))?;
        Ok(())
    }
}
